﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.DataSourcesFile;
using ESRI.ArcGIS.DataSourcesGDB;
using System.IO;
using System.Windows.Forms;
using ESRI.ArcGIS.esriSystem;
using System.Collections;
using ESRI.ArcGIS.Carto;

using PlanningGIS.Win.Controls;
using PlanningGIS.ArcGIS.Custom;
using PlanningGIS.ArcGIS;
using PlanningGIS.Util.Log;

namespace PlanningGIS.DataConvert.model
{
  
    public class DlgDataExportConstruct:DataConstruct 
    {
        private string path;//目标工作空间的路径（如果是SDE则记录连接字符串）
        private zjgisWorkspaceType workspaceType;//工作空间类型
        private bool breaked = false;  //导出构造终止

        private List<string> targetFeatClsNames;//目标要素类的名称
        private List<string> whereClauses;//属性过滤条件

        private bool needCut;//是否需要进行裁切
        private bool isDelNullData;//是否删除空图层
        private IPolygon pPolygon;//空间过滤条件，裁切多边形

        private bool createWsOnly = false;  //仅创建库体

        #region DlgDataExportConstruct members

        /// <summary>
        /// 是否仅创建库体，而不创建数据集和要素类（如果要用GP工具，则该值必须设为True）
        /// </summary>
        public bool CreateWsOnly
        {
            set { createWsOnly = value; }
        }

        /// <summary>
        /// 目标工作空间的路径（如果是SDE则记录连接字符串；如果是GDB或者MDB的数据，不要加后缀）
        /// </summary>
        public string Path
        {
            set { path = value; }
        }

        public zjgisWorkspaceType WorkspaceType
        {
            set { workspaceType = value; }
        }

        public List<string> TargetFeatClsNames
        {
            set { targetFeatClsNames = value; }
        }

        public List<string> WhereClauses
        {
            set { whereClauses = value; }
        }

        public bool NeedCut
        {
            set { needCut = value; }
        }

        public bool IsDelNullData
        {
            set { isDelNullData = value; }
        }

        public IPolygon Geometry
        {
            set { pPolygon = value; }
        }

        public DlgDataExportConstruct()
        {
            needCut = false;
        }        

        #endregion

        public void Stop()
        {
            breaked = true;
        }

        /// <summary>
        /// 构造对应关系（根据数据源创建目标要素类，并形成过滤器，构造字段之间的对应关系）
        /// </summary>
        /// <returns></returns>
        public bool Operate()
        {
            #region 条件判断
            if (path == "")
            {
               LogHelper.WriteErrLog("请设置目标数据的路径！");
                return false;
            }

            if (FeatClsListSource == null || FeatClsListSource.Count == 0)
            {
               LogHelper.WriteErrLog("请选择数据源！");
                return false;
            }

            if (targetFeatClsNames == null || targetFeatClsNames.Count == 0)
            {
               LogHelper.WriteErrLog("请设置目标数据各要素类的名称！");
                return false;
            }
            #endregion

            #region 创建库体
            TargetWs = GetTargetWorkspace();
            if (TargetWs == null) return false;
            #endregion

            #region 创建数据集和要素类，并构造相应关系

            DlgDataConverts = new List<DlgDataConvert>();

            LogHelper.WriteLog("开始创建目标要素类...");

            SetProcessBarMax(FeatClsListSource.Count);

            for (int i = 0; i < FeatClsListSource.Count; i++)
            {
                SetProcessBarCurrent(i + 1);
                if (breaked)
                {
                    return false;
                }
                //if (stopAnyway)
                //    return false;

                IFeatureClass pFeatClsTarget =null ;
                Hashtable fieldRelation =null ;
                if (CreateFeatCls(FeatClsListSource[i], targetFeatClsNames[i], ref pFeatClsTarget, ref fieldRelation))
                {
                    DlgDataConvert dlgDataConvert = new DlgDataConvert();

                    dlgDataConvert.TargetFeatCls = pFeatClsTarget;
                    dlgDataConvert.SourceFeatCls = FeatClsListSource[i];

                    ISpatialFilter pSpatialFilter = new SpatialFilterClass();
                    if (whereClauses!=null) pSpatialFilter.WhereClause = whereClauses[i];
                    if (pPolygon != null) pSpatialFilter.Geometry = pPolygon;
                    pSpatialFilter.GeometryField = FeatClsListSource[i].ShapeFieldName;
                    pSpatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;

                    dlgDataConvert.SpatialFilter = pSpatialFilter;
                    dlgDataConvert.FieldRelation = fieldRelation;

                    dlgDataConvert.NeedDelete = NeedDelete;
                    dlgDataConvert.NeedCut = needCut;
                    dlgDataConvert.IsDelNullData = isDelNullData;
                    dlgDataConvert.CutPolygon = pPolygon;
                    dlgDataConvert.SetProcessBarMax = SetProcessBarMax;
                    dlgDataConvert.SetProcessBarCurrent = SetProcessBarCurrent;
                    

                    //快速导出所需参数
                    dlgDataConvert.WorkspaceType = workspaceType;
                    dlgDataConvert.UseFc2fcGP = createWsOnly;
                    dlgDataConvert.Path = path;
                    dlgDataConvert.TargetFeatClsName = targetFeatClsNames[i];


                    DlgDataConverts.Add(dlgDataConvert);
                }
                //if (stopAnyway) return false;
                Application.DoEvents();
            }
            LogHelper.WriteLog("目标要素类创建完毕。\n");

            #endregion

            return true;
        }

        /// <summary>
        /// 创建目标要素类
        /// </summary>
        /// <param name="pFeatClsSource"></param>
        /// <param name="targetFeatClsName"></param>
        /// <param name="pFeatClsTarget"></param>
        /// <param name="fieldRelation"></param>
        /// <returns></returns>
        private bool CreateFeatCls(IFeatureClass pFeatClsSource,string targetFeatClsName, ref IFeatureClass pFeatClsTarget, ref Hashtable fieldRelation)
        {
            try
            {
                if (createWsOnly) return true;

                IFieldChecker pFieldChecker;
                pFieldChecker = new FieldCheckerClass();
                pFieldChecker.ValidateWorkspace = TargetWs;

                IFeatureDataset pFeatDStarget = null;

                #region 验证要素类名称是否符合规范
                string fixedName = "";
                pFieldChecker.ValidateTableName(targetFeatClsName, out fixedName);
                if (targetFeatClsName != fixedName)
                {
                    LogHelper.WriteLog("目标要素类[" + targetFeatClsName + "]的名称不符合规范，系统自动将其改为[" + fixedName + "]");
                }
                #endregion

                #region 验证要各字段是否符合规范
                IFields pFields = pFeatClsSource.Fields;
                IFields validatedFields = null;
                IEnumFieldError enumFieldError = null;
                pFieldChecker.Validate(pFields, out enumFieldError, out validatedFields);

                fieldRelation = new Hashtable();

                for (int j = 0; j < pFields.FieldCount; j++)
                {
                    fieldRelation.Add(validatedFields.get_Field(j).Name, pFields.get_Field(j).Name);
                }

                //如果需要进行GID的拷贝
                if (FillGuid2)
                {
                    //必须要有GlobalID字段，并且无GlobalID2字段
                    if (pFeatClsSource.Fields.FindField("GlobalID") != -1 && pFeatClsSource.Fields.FindField("GlobalID2") == -1)
                    {
                        IField pField = new FieldClass();
                        IFieldEdit pFieldEdit = pField as IFieldEdit;
                        pFieldEdit.IsNullable_2 = true;
                        pFieldEdit.Editable_2 = true;
                        pFieldEdit.Name_2 = "GlobalID2";
                        //pFieldEdit.AliasName_2 = pFieldInfo.aliasName;
                        pFieldEdit.Type_2 = esriFieldType.esriFieldTypeString;
                        pFieldEdit.Length_2 = 40;

                        (validatedFields as IFieldsEdit).AddField(pField);
                    }
                }

                #endregion


                //对于shape，判断要素类是否存在，对于mdb和gdb还要判断相应的数据集是否存在，另外shape不支持注记
                switch (TargetWs.Type)
                {
                    case esriWorkspaceType.esriFileSystemWorkspace:
                        #region Shape不支持注记
                        if (pFeatClsSource.FeatureType != esriFeatureType.esriFTSimple)
                        {
                           LogHelper.WriteErrLog("目标注记类[" + fixedName + "]创建失败！导出Shape格式只支持点、线、面类型数据，不支持注记等其它类型。");
                            return false;
                        }
                        #endregion

                        #region 判断要素类是否已经存在
                        if (File.Exists(TargetWs.PathName + "\\" + fixedName+".shp"))
                        {
                            pFeatClsTarget = (TargetWs as IFeatureWorkspace).OpenFeatureClass(fixedName);
                            return true;
                        }
                        #endregion

                        #region Shape不能有GlobalID类型的字段
                        for (int i = 0; i < validatedFields.FieldCount; i++)
                        {
                            IField pField = validatedFields.get_Field(i);
                            if (pField.Type == esriFieldType.esriFieldTypeGlobalID) (validatedFields as IFieldsEdit).DeleteField(pField);
                        }
                        #endregion

                        break;

                    case esriWorkspaceType.esriLocalDatabaseWorkspace :
                        IWorkspace2 pWorkspace2 = TargetWs as IWorkspace2;

                        #region 判断数据集是否存在与目标工作空间中
                        if (pFeatClsSource.FeatureDataset != null)
                        {
                            IFeatureDataset pFeatDSsource = pFeatClsSource.FeatureDataset;

                            string fixedDatasetName;
                            fixedDatasetName = pFeatDSsource.Name;
                            if(fixedDatasetName.Contains ('.'))
                            {
                                fixedDatasetName = fixedDatasetName.Substring(fixedDatasetName.LastIndexOf(".") + 1);
                            }
                            pFieldChecker.ValidateTableName(fixedDatasetName, out fixedDatasetName);

                            if (pWorkspace2 != null)
                            {
                                if (pWorkspace2.get_NameExists(esriDatasetType.esriDTFeatureDataset, fixedDatasetName))
                                {
                                    pFeatDStarget = (TargetWs as IFeatureWorkspace).OpenFeatureDataset(fixedDatasetName);
                                }
                                else//如果不存在，需要先创建数据集
                                {
                                    pFeatDStarget = (TargetWs as IFeatureWorkspace).CreateFeatureDataset(fixedDatasetName,
                                        (pFeatDSsource as IGeoDataset).SpatialReference);
                                }
                            }
                        }
                        #endregion

                        #region 判断要素类是否已经存在
                        if (pWorkspace2.get_NameExists(esriDatasetType.esriDTFeatureClass, fixedName))
                        {
                            pFeatClsTarget = (TargetWs as IFeatureWorkspace).OpenFeatureClass(fixedName);
                            return true;
                        }
                        #endregion

                        break;

                    case esriWorkspaceType.esriRemoteDatabaseWorkspace :

                        return false;
                }

                switch (pFeatClsSource.FeatureType)
                {
                    #region 创建要素类
                    case esriFeatureType.esriFTSimple:
                        if (pFeatDStarget != null)
                        {
                            pFeatClsTarget = pFeatDStarget.CreateFeatureClass(fixedName, validatedFields, null, null,
                                esriFeatureType.esriFTSimple, "Shape", "");
                        }
                        else
                        {
                            pFeatClsTarget = (TargetWs as IFeatureWorkspace).CreateFeatureClass(fixedName, validatedFields,
                                null, null, esriFeatureType.esriFTSimple, "Shape", "");
                        }
                        LogHelper.WriteDoneLog("目标要素类[" + fixedName + "]创建成功。");
                        break;
                    #endregion

                    #region 创建注记类
                    case esriFeatureType.esriFTAnnotation:
                        pFeatClsTarget = GeodatabaseHelper.CreateAnnotationFeatureClass(TargetWs, fixedName, validatedFields, pFeatClsSource, pFeatDStarget);
                        LogHelper.WriteDoneLog("目标注记类[" + fixedName + "]创建成功。");
                        break;
                    #endregion

                    #region 暂不支持的类型
                    default:
                       LogHelper.WriteErrLog("系统暂不支持[" + pFeatClsSource.AliasName + "]数据（类型为[" + pFeatClsSource.FeatureType.ToString() + "]）的导出！");
                        return false;
                    #endregion
                }

                #region 给要素类赋别名

                if (pFeatClsTarget == null) return false;

                try
                {

                    IClassSchemaEdit pClassSchemaEdit = pFeatClsTarget as IClassSchemaEdit;
                    //shape没有别名
                    if (pClassSchemaEdit != null) pClassSchemaEdit.AlterAliasName(pFeatClsSource.AliasName);
                }
                catch (Exception ex)
                {
                   LogHelper.WriteErrLog("给目标要素类[" + fixedName + "]赋别名时出错：" + ex.Message);
                }
                #endregion

                return true;
            }
            catch (Exception e)
            {
               LogHelper.WriteErrLog("创建要素类[" + targetFeatClsName + "]失败！" + e.Message);
                return false;
            }

        }

        /// <summary>
        /// 创建目标库体
        /// </summary>
        /// <returns></returns>
        private IWorkspace GetTargetWorkspace()
        {
            try
            {
                IWorkspaceFactory pWorkspaceFactory;

                //获得路径和文件名（测试以下，仅选择驱动器看会有什么样的异常）
                int pos = path.LastIndexOf('\\');
                string strPath = path.Substring(0, pos + 1);
                string strName = path.Substring(pos + 1);
                
                //对于大比例尺的图幅，图号中有'.'，需要去掉，不然创建不了库体
                strName = strName.Replace(".", "");

                string fullPath;

                switch (workspaceType)
                {
                    case zjgisWorkspaceType.shp:
                        pWorkspaceFactory = new ShapefileWorkspaceFactoryClass();

                        //如果文件夹不存在，需要先创建
                        if (!Directory.Exists(path))
                            Directory.CreateDirectory(path);

                        return pWorkspaceFactory.OpenFromFile(path, 0);

                    case zjgisWorkspaceType.mdb:
                    case zjgisWorkspaceType.gdb:
                        //如果文件夹不存在，需要先创建（与Shape不一样，这里创建到上一级）
                        if (!Directory.Exists(strPath))
                            Directory.CreateDirectory(strPath);

                        if (workspaceType == zjgisWorkspaceType.mdb)
                        {
                            pWorkspaceFactory = new AccessWorkspaceFactoryClass();
                            fullPath = strPath  + strName + ".mdb";
                        }
                        else
                        {
                            pWorkspaceFactory = new FileGDBWorkspaceFactoryClass();
                            fullPath = strPath  + strName + ".gdb";
                        }

                        if ((workspaceType == zjgisWorkspaceType.mdb && File.Exists(fullPath)) ||
                            (workspaceType == zjgisWorkspaceType.gdb && Directory.Exists(fullPath)))
                        {
                            DialogResult dialogresult = MsgHelper.ShowYesNoCancelQueryMsgbox("目标工作空间已经存在，追加导出请点击“是”，删除原有数据并创建新工作空间请点击“否”，终止本次导出请点击“取消”。");
                            switch (dialogresult)
                            {
                                case DialogResult.Yes:
                                    return pWorkspaceFactory.OpenFromFile(fullPath, 0);

                                case DialogResult.No:
                                    try
                                    {
      

                                        IWorkspace pWs = pWorkspaceFactory.OpenFromFile(fullPath, 0);
                                        if (pWs != null)
                                        {
                                            IDataset pDataset = pWs as IDataset;
                                            if (pDataset.CanDelete())
                                            {
                                                pDataset.Delete();
                                            }
                                            else
                                            {
                                                MsgHelper.ShowWarningMsgbox("目标数据库无法被删除，可能其它进程正在使用该数据，请检查！");
                                                return null;
                                            }

                                        }
                                        //如果不能通过AE接口打开，说明该数据已经被损坏，则直接通过文件或者文件夹的方式删除
                                        else
                                        {
                                            if (workspaceType == zjgisWorkspaceType.mdb)
                                                File.Delete(fullPath);
                                            else
                                            {
                                                foreach (string filename in Directory.GetFiles(fullPath))
                                                    File.Delete(filename);

                                                Directory.Delete(fullPath);
                                            }
                                        }

                                    }
                                    catch (Exception e)
                                    {
                                       LogHelper.WriteErrLog("删除已有目标数据工作空间失败！" + e.Message);
                                        return null;
                                    }

                                    break;

                                case DialogResult.Cancel:
                                    return null;
                            }
                        }
                        break;

                    case zjgisWorkspaceType.sde:
                       LogHelper.WriteErrLog("数据导出暂时不支持导出到SDE！");
                        return null;

                    default:
                       LogHelper.WriteErrLog("导出工作空间类型异常，系统目前仅支持导出shp、mdb和gdb格式！");
                        return null;
                }

                IWorkspaceName pWorkspaceName = pWorkspaceFactory.Create(strPath, strName, null, 0);

                IName pName = (IName)pWorkspaceName;
                return (IWorkspace)pName.Open();
 
            }
            catch (Exception e)
            {
               LogHelper.WriteErrLog("创建目标库体失败！" + e.Message);
                return null;
            }
       }
    
    }
}
